﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Language;
using LuaC;
using LuaInterface;
using System.Threading;

namespace LuaBoard
{
    public class LuaItem
    {
        private LanguageData lang = Language.CommLanguageData.data;

        private string _Text = "";
        private string _Name = "";
        private LuaClass luac;
        private DirectoryInfo _dir;
        private int _ImageIndex = 2;
        public bool CanRun = true;
        public bool HaveContextMenu = false;
        public bool HaveInfo = false;
        public List<LuaItem> sublp;
        public TreeNode tn;
        public TreeNode UpTreeNode;
        public string RelatedFile;
        public int RelatedFileIconIndex = 0;
        private LuaItem Parent;
        private List<LuaItem_menu> menus;
        public ListViewItem lviTag = null;
        public LuaBoard MainForm;
        public AppLoc apploc = null;
        

        public bool NoApploc = false; //disable Apploc
        public bool NoArguments = false; //disable Arguments

        public List<ToolStripItem> LuaFilePath = new List<ToolStripItem>();

        private string arguments = "";

        public bool? IsFolder
        {
            get 
            {
                if (luac == null) return null;
                if (luac.LuaVM["IsFolder"] == null) return true;
                return (bool?)luac.LuaVM["IsFolder"];
            }
        }

        public string Arguments
        {
            get { return arguments; }
            set
            {
                arguments = value;
                string newarg = arguments.Replace(@"\", @"\\").Replace("\"", "\\\"");
                string code = string.Format("setting=setting or {0} setting.Arguments='{1}'", "{}",newarg);
                luac.LuaVM.DoString(code);
                SaveSetting();
            }
        }
        public bool? isShortcut
        {
            get
            {
                if (luac == null) return null;
                if (luac.LuaVM["setting"] == null) return null;
                return (bool?)luac.LuaVM["setting.IsShortcut"];
            }
            set
            {
                if (value == null) return;
                if (luac == null) return;
                if (luac.LuaVM["setting"] == null) luac.LuaVM.NewTable("setting");
                luac.LuaVM["setting.IsShortcut"] = value;
                SaveSetting();
            }
        }

        public LuaItem(string name, DirectoryInfo dir, LuaItem parent,bool? IsShortcut,bool isFolder)
        {
            _Name = name;
            _Text = name;
            _dir = dir;
            Parent = parent;

            ListViewItem item = new ListViewItem(name);
            item.Tag = (object)this;
            item.ImageIndex = _ImageIndex;
            lviTag = item;
            MainForm = LuaListView._main;

            try
            {
                luac = new LuaClass(name, _dir.FullName);

                luac.LuaVM["MainForm"] = MainForm;
                luac.LuaVM["SelfItem"] = this;
                luac.LuaVM["ParentItem"] = Parent;
                luac.LuaVM["MainTabPages"] = LuaListView._MainTabs;
                luac.LuaVM["IsFolder"] = isFolder;
                if (IsShortcut != null)
                {
                    if (luac.LuaVM["setting"] == null) luac.LuaVM.NewTable("setting");
                    luac.LuaVM["setting.IsShortcut"] = IsShortcut;
                }

                #region Register Function
                luac.LuaVM.RegisterFunction("board.ChangeMenuIconPath", this, this.GetType().GetMethod("ChangeMenuIconPath"));
                luac.LuaVM.RegisterFunction("board.ChangeMenuIconKey", this, this.GetType().GetMethod("ChangeMenuIconKey"));
                luac.LuaVM.RegisterFunction("board.ChangeMenuText", this, this.GetType().GetMethod("ChangeMenuText"));
                luac.LuaVM.RegisterFunction("Process.run", this, this.GetType().GetMethod("RunExe"));

                #endregion

                //Plugins
                MainForm.RegisterLua(luac.LuaVM);
            }
            catch (Exception e)
            {

                luac.PutErrorEx(e);
            }

            if (Common.AppLocEnable) apploc = new AppLoc(this);

        }
        public void Close()
        {
            try
            {
                object[] ret;
                LuaFunction function = (LuaFunction)luac.LuaVM["CallPlot_Close"];

                
                if (function != null)
                {
                    while (true)
                    {
                        ret = function.Call();
                        if (ret != null && ret.Length > 0 && ret[0] != null)
                        {
                            if ((bool)ret[0]) Thread.Sleep(200);
                            else break;
                        }
                        else break;

                    }
                }
                luac.Close();
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }
        }
        public void SaveSetting()
        {
            try
            {
                LuaFunction function = (LuaFunction)luac.LuaVM["SaveSetting"];
                if (function != null) function.Call();
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }

        }

        public string Text
        {
            get 
            {
                try
                {
                    luac.LuaVM.DoString("setting=setting or {}");
                    _Text = (string)luac.LuaVM["setting.Title"];
                }
                catch (Exception e)
                {
                    luac.PutErrorEx(e);
                }
                return _Text; 
            }
            set 
            {

                if (_Text == value) return;
                try
                {
                    luac.LuaVM.DoString("setting=setting or {}");
                    luac.LuaVM.DoString(string.Format("setting.Title='{0}'", value));
                    _Text = value;
                }
                catch (Exception e)
                {
                    luac.PutErrorEx(e);
                }
                if (lviTag != null)
                {
                    lviTag.Text = _Text;
                }
            }
        }
        public DirectoryInfo dir
        {
            get { return _dir; }
        }
        public LuaClass Luac
        {
            get { return luac; }
        }
        public int ImageIndex
        {
            get { return _ImageIndex; }
            set { _ImageIndex = value; }
        }
        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }
        public string DirName
        {
            get { return _dir.Name; }
            set
            {
                try
                {
                    string dirname = value;
                    string path = _dir.Parent.FullName + @"\" + value;
                    if (Directory.Exists(path))
                    {
                        luac.PutError("Directory already exists.(" + path + ")");
                        return;
                    }
                    _dir.MoveTo(path);

                    luac.Name = dirname;
                    _Name = dirname;
                }
                catch (Exception e)
                {
                    luac.PutError(string.Format("{0}", e.Message));
                }
            }
        }

        #region lua function
        public void ChangeMenuIconPath(string path,int index)
        {
            if (File.Exists(path))
            {
                RelatedFile = path;
                RelatedFileIconIndex = index;
                LuaListView.AddImageList(this);
                lviTag.ImageKey = RelatedFile;
            }
        }
        public void ChangeMenuIconKey(string key)
        {
            lviTag.ImageKey = key;
        }
        public void ChangeMenuText(string text)
        {
            Text = text;
        }
        public void RunExe(string path, string Arguments, string WorkingDirectory)
        {
            if (!File.Exists(path))
            {
                luac.PutError(string.Format("{0}({1})", lang.GetString("File does not exist."), path));
                return;
            }
            if (!Directory.Exists(WorkingDirectory))
            {
                //luac.PutError(string.Format("{0}({1})", lang.GetString("Directory does not exist."), WorkingDirectory));
                WorkingDirectory = Path.GetDirectoryName(path);
            }

            Process run = new Process();

            if (Common.AppLocEnable && apploc.Enable)
            {
                run.StartInfo.FileName = Path.GetFullPath(Common.AppLocPath);
                run.StartInfo.Arguments = string.Format("\"{0}\" {1} \"{2}\"", Path.GetFullPath(path), Arguments, apploc.key);
                if (WorkingDirectory=="")
                    run.StartInfo.WorkingDirectory = Path.GetFullPath(Path.GetDirectoryName(path));
                else
                    run.StartInfo.WorkingDirectory = Path.GetFullPath(WorkingDirectory);
                run.Start();
            }
            else
            {
                run.StartInfo.FileName = Path.GetFullPath(path);
                run.StartInfo.Arguments = Arguments;
                if (WorkingDirectory == "")
                    run.StartInfo.WorkingDirectory = Path.GetFullPath(Path.GetDirectoryName(run.StartInfo.FileName));
                else
                    run.StartInfo.WorkingDirectory = Path.GetFullPath(WorkingDirectory);
                run.Start();
            }
        }

        #endregion

        private void LuaPath_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = (ToolStripMenuItem)sender;
            FileInfo file = (FileInfo)tsmi.Tag;
            ProcessStartInfo sInfo = new ProcessStartInfo(file.FullName);
            Process.Start(sInfo);
        }

        public void LoadLuaSystem()
        {
            string path = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, @"system");
            DirectoryInfo dir = new DirectoryInfo(path);
            if (!dir.Exists)
            {
                //throw new Exception("lua directory doesn't exist.");
                return;
            }
            LoadLuaLoopDir(dir);
        }

        private void LoadLuaLoopDir(DirectoryInfo dir)
        {

            DirectoryInfo[] dirs;


            LoadLuaLoopFiles(dir,false);

            dirs = dir.GetDirectories();
            if (dirs.Length > 0)
                foreach (DirectoryInfo d in dirs)
                {
                    LoadLuaLoopDir(d);
                }
        }

        private void LoadLuaLoopFiles(DirectoryInfo dir,bool menuitem)
        {
            Language.CommLanguageData.data.LoadINI(dir.FullName);

            FileInfo[] files;
            files = dir.GetFiles("setting.lua");
            if (files.Length > 0)
            {
                this.luac.DoFileUnicode(files[0].FullName);
            }
            files = dir.GetFiles("*.lua");
            foreach (FileInfo file in files)
            {
                if (file.Extension.ToLower() == ".lua")
                {
                    if (menuitem)
                    {
                        ToolStripItem li = new ToolStripMenuItem(file.Name);
                        li.Click += new EventHandler(LuaPath_Click);
                        li.Tag = file;
                        LuaFilePath.Add(li);
                    }
                    if (file.Name.ToLower() != "setting.lua")
                        this.luac.DoFileUnicode(file.FullName);
                }
            }
        }
        public void CallPlot_Check()
        {
            try
            {
                object[] ret;
                LuaFunction function = (LuaFunction)luac.LuaVM["CallPlot_Check"];

                if (function != null)
                {
                    function.Call();
                }
                if ((bool?)luac.LuaVM["NoApploc"] == true) NoApploc = true;
                if ((bool?)luac.LuaVM["NoArguments"] == true) NoArguments = true;

                function = (LuaFunction)luac.LuaVM["CallPlot_GetIconPath"];
                if (function != null)
                {
                    ret = function.Call();
                    if (ret != null && ret.Length > 0 && ret[0] != null)
                    {
                        RelatedFile = (string)ret[0];
                        if (ret.Length > 1)
                        {
                            RelatedFileIconIndex = (int)(double)ret[1];
                        }
                        LuaListView.AddImageList(this);
                        lviTag.ImageKey = RelatedFile;

                    }
                }

                function = (LuaFunction)luac.LuaVM["CallPlot_ContextMenu"];
                if (function != null)
                {
                    ret = function.Call();
                    if (ret != null && ret.Length > 0 && ret[0] != null)
                    {
                        Type t = typeof(LuaInterface.LuaTable);
                        if (ret[0].GetType() == t)
                        {
                            HaveContextMenu = true;
                            int counter = 0;
                            menus = new List<LuaItem_menu>();
                            foreach (DictionaryEntry tab in (LuaTable)ret[0])
                            {
                                LuaInterface.LuaTable li = (LuaTable)tab.Value;
                                LuaItem_menu lim = new LuaItem_menu(this, _Name, li, ref counter);
                                menus.Add(lim);
                            }
                        }
                    }
                }

                function = (LuaFunction)luac.LuaVM["CallPlot_Info"];
                if (function != null)
                {
                    ret = function.Call();
                    if (ret != null && ret.Length > 0 && ret[0] != null)
                    {
                        if (ret[0] is string)
                        {
                            HaveInfo = true;
                        }
                    }
                }

                //read setting
                if (luac.LuaVM["setting"] != null)
                {
                    string settingTitle = (string)luac.LuaVM["setting.Title"];
                    if (settingTitle != null && settingTitle != "")
                    {
                        Text = lang.GetString(settingTitle);
                    }

                    string Apploc = (string)luac.LuaVM["setting.AppLoc"];

                    if (Apploc != null && Apploc != "")
                    {
                        this.apploc.Setup(Apploc);
                    }
                    string Arguments = (string)luac.LuaVM["setting.Arguments"];

                    if (Arguments != null && Arguments != "")
                    {
                        this.arguments = Arguments;
                    }
                }

            }
            catch (Exception e)
            {

                luac.PutErrorEx(e);
            }

        }
        public void LoadLuaToLuaVM(DirectoryInfo dir)
        {
            LoadLuaLoopFiles(dir,true);
            
            try
            {
                LuaFunction function = (LuaFunction)luac.LuaVM["CallPlot_Run"];
                if (function != null)
                    CanRun = true;
                else
                    CanRun = false;
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }
        }

        public void Reload_ContextMenu()
        {
            try
            {
                LuaFunction function = (LuaFunction)luac.LuaVM["CallPlot_ContextMenu"];
                if (function != null)
                {
                    object[] ret;
                    ret = function.Call();
                    if (ret != null && ret.Length > 0 && ret[0] != null)
                    {
                        Type t = typeof(LuaInterface.LuaTable);
                        if (ret[0].GetType() == t)
                        {
                            HaveContextMenu = true;
                            int counter = 0;
                            menus = new List<LuaItem_menu>();
                            foreach (DictionaryEntry tab in (LuaTable)ret[0])
                            {
                                LuaInterface.LuaTable li = (LuaTable)tab.Value;
                                LuaItem_menu lim = new LuaItem_menu(this, _Name, li, ref counter);
                                menus.Add(lim);
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }
        }
        public string[] GetInfo()
        {
            string[] r = new string[0];

            if (!HaveInfo) return r;
            try
            {
                LuaFunction function = (LuaFunction)luac.LuaVM["CallPlot_Info"];
                if (function != null)
                {
                    object[] ret = function.Call();
                    if (ret!=null && ret.Length>0 && ret[0] is string)
                    {
                        r = new string[ret.Length];
                        for (int i = 0; i < ret.Length; i++) r[i] = (string)ret[i];
                        return r; 
                    }
                }
                
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }

            return r;
        }

        public void RunLua()
        {
            if (!CanRun) return;
            try
            {
                LuaFunction function = (LuaFunction)luac.LuaVM["CallPlot_Run"];
                if (function != null) function.Call();
                else
                    luac.PutError(string.Format("{0} CallPlot_Run",lang.GetString("Can not find the lua function :")));
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }
        }
        public void MenuClick(LuaItem_menu menu)
        {
            if (menu.CallPlot == "") return;//DateTime.Now.AddMinutes()

            if (menu.check != null)
            {
                menu.check = !menu.check;
            }
            
            try
            {
                LuaFunction function = (LuaFunction)luac.LuaVM[menu.CallPlot];
                if (function != null) function.Call();
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }
        }
        public void AppLocSetup(string code)
        {
            try
            {
                luac.LuaVM.DoString("setting=setting or {}");
                luac.LuaVM["setting.AppLoc"] = code;
                if (code == "") luac.LuaVM.DoString("setting.AppLoc=nil");
                SaveSetting();
                
            }
            catch (Exception e)
            {
                luac.PutErrorEx(e);
            }
        }
        public void AddContextMenu(ContextMenuStrip cm)
        {
            if (!HaveContextMenu) return;
            foreach (LuaItem_menu lim in menus)
            {
                if (!cm.Items.Contains(lim.tsi))
                {
                    cm.Items.Add(lim.tsi);
                    lim.tsi.Click += new System.EventHandler(this.LuaMenuItem_Click);
                    if (lim.HaveSub)
                    {
                        AddContextMenuSub((ToolStripMenuItem)lim.tsi, lim.sub_menu);
                    }
                }
                else
                    lim.tsi.Visible = true;
            }
        }
        private void AddContextMenuSub(ToolStripMenuItem tsi,List<LuaItem_menu> lims)
        {
            foreach (LuaItem_menu lim in lims)
            {
                tsi.DropDownItems.Add(lim.tsi);
                if (lim.CallPlot != "") lim.tsi.Click += new System.EventHandler(this.LuaMenuItem_Click);
                if (lim.HaveSub)
                {
                    AddContextMenuSub(tsi, lim.sub_menu);
                }
            }
        }

        private void LuaMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = (ToolStripMenuItem)sender;
            LuaItem_menu lim = (LuaItem_menu)tsmi.Tag;
            lim.MenuClick();
        }

        public bool delete()
        {
            if (_dir.Exists)
            {
                _dir.Delete(true);
            }
            return _dir.Exists;
        }
        public void Remove()
        {
            Parent.sublp.Remove(this);
        }
        public override string ToString()
        {
            return Name;
        }
    }

    public class LuaItem_menu
    {
        public ToolStripItem tsi;
        public List<LuaItem_menu> sub_menu;
        public string CallPlot = "";
        private bool? Check;
        private LuaItem lp;

        public bool? check
        {
            get { return Check; }
            set
            {
                Check = value;
                if (Check == null) return;
                if (tsi is ToolStripMenuItem)
                {
                    ToolStripMenuItem tsmi = (ToolStripMenuItem)tsi;
                    tsmi.Checked = (bool)Check;
                }
            }
        }
        public bool HaveSub
        {
            get
            {
                if (sub_menu != null)
                    return true;
                else
                    return false;
            }
        }

        public LuaItem_menu(LuaItem LI,string name, LuaTable table,ref int counter)
        {
            lp = LI;
            string text = (string)table[1];
            if (text == "")
            {
                tsi = new ToolStripSeparator();
                tsi.Tag = (object)this;
                tsi.Name = name + "_" + counter.ToString(); counter++;
                return;
            }
            CallPlot = (string)table[2];
            ToolStripMenuItem tsmi = new ToolStripMenuItem();
            tsmi.Name = name + "_" + (string)table[1] + counter.ToString(); counter++;
            tsmi.Text = text;
            tsi = tsmi;
            
            if (table[3] != null)
            {
                check = (bool)table[3];
            }
            if (table[4] != null && table[4] is LuaTable)
            {
                sub_menu = new List<LuaItem_menu>();

                foreach (DictionaryEntry tab in (LuaTable)table[4])
                {
                    LuaTable li = (LuaTable)tab.Value;
                    LuaItem_menu lim = new LuaItem_menu(LI, tsmi.Name, li,ref counter);
                    sub_menu.Add(lim);
                    tsmi.DropDownItems.Add(lim.tsi);
                }

            }
            tsmi.Tag = (object)this;
            
        }
        public void MenuClick()
        {
            lp.MenuClick(this);
        }
        
    }

    public class AppLoc
    {
        public LuaItem lp;
        public bool Enable = false;
        public string key = "";

        public AppLoc(LuaItem LI)
        {
            lp = LI;
        }
        public void Setup(string code)
        {
            if (code.Length == 6 && code.Substring(0, 2) == "/L")
            {
                key = code;
                Enable = true;
                return;
            }
            switch (code.ToLower())
            {
                case ("simplified chinese"):
                    key = "/L0804";
                    break;
                case ("korean"):
                    key = "/L0412";
                    break;
                case ("japanese"):
                    key = "/L0411";
                    break;
                case ("traditional chinese"):
                    key = "/L0404";
                    break;
            }
            if (code != "" && key != "")
                Enable = true;
            else
                Enable = false;
            
            lp.AppLocSetup(key);
            lp.apploc.key = key;
        }
    }

    public class LuaTableItem
    {
        public LuaInterface.LuaTable table;
        public string text = "";
        public override string ToString()
        {
            if (text != "") return text;
            return base.ToString();
        }
    }
}
